/*
 * Copyright (c) Huawei Device Co., Ltd. 2023. All rights reserved.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "channel.h"
#include "loghelper.h"
#include "isecure_element_channel.h"
#include "se_service.h"
#include "session.h"

using namespace std;

namespace OHOS {
namespace SE {
namespace OMAPI {

Channel::Channel(std::weak_ptr<SEService> service,
                 std::weak_ptr<Session> session,
                 sptr<ISecureElementChannel> channel)
    : boundSession_(session), channelIface_(channel), boundService_(service)
{
}

Channel::~Channel() {}

int Channel::InnerCheckChannelStatus(void)
{
    // don't lock for mutex_ here, already locked outter.
    if (boundService_.expired() || !channelIface_) {
        ErrorLog("InnerCheckChannelStatus boundService_ or readerIface_ is null!");
        return ErrorCode::SE_ILLEGAL_STATE_ERROR;
    }
    return ErrorCode::SE_SUCCESS;
}

int Channel::Close(void)
{
    {
        std::lock_guard<std::mutex> lock(mutex_);
        int ret = InnerCheckChannelStatus();
        if (ret != ErrorCode::SE_SUCCESS) {
            ErrorLog("Close failed, res = %{public}d", ret);
            return ret;
        }
    }

    {
        // already lock for mutex_ in 'IsClosed'
        bool isClosed = true;
        int ret = IsClosed(isClosed);
        if (isClosed) {
            WarnLog("Channel is alreadly closed, ret = %{public}d", ret);
            return ErrorCode::SE_SUCCESS;
        }
    }

    std::lock_guard<std::mutex> lock(mutex_);
    return channelIface_->Close();
}

int Channel::IsClosed(bool &isClosed)
{
    std::lock_guard<std::mutex> lock(mutex_);
    isClosed = false;
    if (boundService_.expired() || !channelIface_) {
        ErrorLog("IsClosed boundService_ or channelIface_ is null!");
        return ErrorCode::SE_ILLEGAL_STATE_ERROR;
    }
    return channelIface_->IsClosed(isClosed);
}

int Channel::IsBasicChannel(bool &isBasicChannel)
{
    std::lock_guard<std::mutex> lock(mutex_);
    isBasicChannel = false;
    int ret = InnerCheckChannelStatus();
    if (ret != ErrorCode::SE_SUCCESS) {
        ErrorLog("IsBasicChannel failed, res = %{public}d", ret);
        return ret;
    }

    return channelIface_->IsBasicChannel(isBasicChannel);
}

int Channel::GetSelectResponse(std::string &selectResponse)
{
    std::lock_guard<std::mutex> lock(mutex_);
    selectResponse = std::string();
    int ret = InnerCheckChannelStatus();
    if (ret != ErrorCode::SE_SUCCESS) {
        ErrorLog("GetSelectResponse failed, res = %{public}d", ret);
        return ret;
    }

    return channelIface_->GetSelectResponse(selectResponse);
}

int Channel::Transmit(const std::string &command, std::string& response)
{
    std::lock_guard<std::mutex> lock(mutex_);
    response = std::string();
    int ret = InnerCheckChannelStatus();
    if (ret != ErrorCode::SE_SUCCESS) {
        ErrorLog("Transmit failed, res = %{public}d", ret);
        return ret;
    }

    return channelIface_->Transmit(command, response);
}

int Channel::SelectNext(bool &selectStatus)
{
    std::lock_guard<std::mutex> lock(mutex_);
    selectStatus = false;
    int ret = InnerCheckChannelStatus();
    if (ret != ErrorCode::SE_SUCCESS) {
        ErrorLog("SelectNext failed, res = %{public}d", ret);
        return ret;
    }

    return channelIface_->SelectNext(selectStatus);
}

int Channel::GetSession(std::weak_ptr<Session> &session)
{
    std::lock_guard<std::mutex> lock(mutex_);
    session = boundSession_;
    return ErrorCode::SE_SUCCESS;
}
}  // namespace OMAPI
}  // namespace SE
}  // namespace OHOS